package com.zkmonitor.controller;

import com.zkmonitor.common.Auth;
import com.zkmonitor.common.Jurisdiction;
import com.zkmonitor.common.LoginRequired;
import com.zkmonitor.common.UserHolder;
import com.zkmonitor.exception.ShepherException;
import com.zkmonitor.model.User;
import com.zkmonitor.service.NodesService;
import com.zkmonitor.util.ClusterUtil;
import com.zkmonitor.util.ParamUtils;
import com.zkmonitor.util.ParentPathParser;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;
import java.util.Map.Entry;

@Controller
@LoginRequired
@RequestMapping("/clusters/{cluster}/nodes")
public class NodesController {

	private static final String SLASH = "/";

	@Autowired
	private NodesService nodeService;

	@Autowired
	private UserHolder userHolder;

	/**
	 * Lists nodes of the cluster.
	 *
	 * @param path
	 * @param cluster
	 * @param showIp
	 * @param model
	 * @return
	 * @throws ShepherException
	 */
	@RequestMapping(value = "", method = RequestMethod.GET)
	public String home(
			@RequestParam(value = "path", defaultValue = SLASH) String path,
			@PathVariable("cluster") String cluster,
			@RequestParam(value = "show-ip", defaultValue = "") String showIp,
			Model model) throws ShepherException {

		List<String> children = nodeService.getChildren(cluster, path);

		String role = userHolder.getUser().getRole();
		boolean hasPermission = role.equals(User.ROLE_ADMIN);
		boolean hasDeletePermission = role.equals(User.ROLE_ADMIN);

		Entry<List<ACL>, Stat> statAcl = nodeService.getStatWithACL(cluster,
				path);
		model.addAttribute("children", children);
		model.addAttribute("hasChild", !children.isEmpty());
		model.addAttribute("data", StringEscapeUtils.escapeHtml4(nodeService
				.getData(cluster, path)));
		model.addAttribute("stat", nodeService.getStat(cluster, path));
		model.addAttribute("acls", statAcl.getKey());
		model.addAttribute("path", path);
		model.addAttribute("pathArr", path.split(SLASH));
		model.addAttribute("cluster", cluster);
		model.addAttribute("clusters", ClusterUtil.getClusters());
		model.addAttribute("hasPermission", hasPermission);
		model.addAttribute("hasDeletePermission", hasDeletePermission);
		model.addAttribute("isOnebox", false);
		model.addAttribute("showIp", showIp);

		return "/cluster/index";
	}

	/**
	 * Updates node of the cluster.
	 *
	 * @param path
	 * @param cluster
	 * @param data
	 * @param model
	 * @return
	 * @throws ShepherException
	 */
	@Auth(Jurisdiction.SUPER_ADMIN)
	@RequestMapping(value = "/update", method = RequestMethod.POST)
	public String update(
			@RequestParam("path") String path,
			@PathVariable("cluster") String cluster,
			@RequestParam(value = "data") String data,
			@RequestParam(value = "srcPath", defaultValue = "/") String srcPath,
			@RequestParam(value = "srcCluster", defaultValue = "") String srcCluster,
			Model model) throws ShepherException {
		String tempData = data;
		if (!("/".equals(srcPath)) && !("".equals(srcCluster))) {
			tempData = nodeService.getData(srcCluster, srcPath);
		}

		User user = userHolder.getUser();
		nodeService.update(cluster, path, tempData, user.getName());
		return "redirect:/clusters/" + cluster + "/nodes?path="
				+ ParamUtils.encodeUrl(path);

	}

	/**
	 * Deletes node of the cluster.
	 *
	 * @param path
	 * @param cluster
	 * @param model
	 * @return
	 * @throws ShepherException
	 */
	@Auth(Jurisdiction.SUPER_ADMIN)
	@RequestMapping(value = "/delete", method = RequestMethod.POST)
	public String delete(@RequestParam("path") String path,
			@PathVariable("cluster") String cluster, Model model)
			throws ShepherException {
		User user = userHolder.getUser();
		String parentPath = ParentPathParser.getParent(path);
		nodeService.delete(cluster, path, user.getName());
		return "redirect:/clusters/" + cluster + "/nodes?path="
				+ ParamUtils.encodeUrl(parentPath);
	}

	/**
	 * Displays the page of node creation.
	 *
	 * @param path
	 * @param cluster
	 * @param showIp
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/create", method = RequestMethod.GET)
	public String create(
			@RequestParam(value = "path", defaultValue = SLASH) String path,
			@PathVariable("cluster") String cluster,
			@RequestParam(value = "show-ip", defaultValue = "") String showIp,
			Model model) throws ShepherException {
		List<String> children = nodeService.getChildren(cluster, path);

		String data = nodeService.getData(cluster, path);
		String[] pathArr = path.split(SLASH);

		model.addAttribute("children", children);
		model.addAttribute("data", data);
		model.addAttribute("path", path);
		model.addAttribute("pathArr", pathArr);
		model.addAttribute("cluster", cluster);
		model.addAttribute("clusters", ClusterUtil.getClusters());
		model.addAttribute("isOnebox", false);

		return "/cluster/create";
	}

	/**
	 * Creates node of the cluster.
	 *
	 * @param parent
	 * @param data
	 * @param child
	 * @param cluster
	 * @param model
	 * @return
	 * @throws ShepherException
	 */
	@RequestMapping(value = "/create", method = RequestMethod.POST)
	public String create(@RequestParam("path") String parent,
			@RequestParam("data") String data,
			@RequestParam("child") String child,
			@PathVariable("cluster") String cluster, Model model)
			throws ShepherException {
		User user = userHolder.getUser();
		String path = parent + SLASH + child;
		if (parent.equals(SLASH)) {
			path = SLASH + child;
		}
		nodeService.create(cluster, path, data, user.getName());

		return "redirect:/clusters/" + cluster + "/nodes?path="
				+ ParamUtils.encodeUrl(path);
	}
}
